/*
 * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE
 * file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file
 * to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
 * License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */

package com.swak.monitor.dubbo.web;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.dubbo.metadata.definition.model.FullServiceDefinition;
import org.apache.dubbo.metadata.report.identifier.MetadataIdentifier;
import org.springframework.beans.factory.annotation.Autowired;

import com.swak.annotation.Get;
import com.swak.annotation.Post;
import com.swak.annotation.RestApi;
import com.swak.monitor.dubbo.model.domain.Consumer;
import com.swak.monitor.dubbo.model.domain.Provider;
import com.swak.monitor.dubbo.model.dto.MetricDTO;
import com.swak.monitor.dubbo.model.dto.RelationDTO;
import com.swak.monitor.dubbo.service.ConsumerService;
import com.swak.monitor.dubbo.service.MetricsService;
import com.swak.monitor.dubbo.service.ProviderService;
import com.swak.monitor.dubbo.service.impl.MetrcisCollectServiceImpl;
import com.swak.monitor.dubbo.utils.Constants;
import com.swak.monitor.dubbo.utils.Tool;
import com.swak.utils.JsonMapper;

@RestApi(value = "DubboMetricsCollectApi", path = "/api/monitor/:env/metrics")
public class MetricsCollectApi {

    @Autowired
    private ProviderService providerService;
    @Autowired
    private ConsumerService consumerService;
    @Autowired
    private MetricsService metricsService;

    @Post
    public String metricsCollect(String group, String env) {
        MetrcisCollectServiceImpl service = new MetrcisCollectServiceImpl();
        service.setUrl("dubbo://127.0.0.1:20880?scope=remote&cache=true");

        return service.invoke(group).toString();
    }

    @Get("/relation")
    public RelationDTO getApplicationRelation() {
        return metricsService.getApplicationRelation();
    }

    private String getOnePortMessage(String group, String ip, String port, String protocol) {
        MetrcisCollectServiceImpl metrcisCollectService = new MetrcisCollectServiceImpl();
        metrcisCollectService.setUrl(protocol + "://" + ip + ":" + port + "?scope=remote&cache=true");
        String res = metrcisCollectService.invoke(group).toString();
        return res;
    }

    @Get("/ipAddr")
    public List<MetricDTO> searchService(String ip, String group, String env) {

        Map<String, String> configMap = new HashMap<>();
        addMetricsConfigToMap(configMap, ip);

        // default value
        if (configMap.size() <= 0) {
            configMap.put("20880", "dubbo");
        }
        List<MetricDTO> metricDTOS = new ArrayList<>();
        for (String port : configMap.keySet()) {
            String protocol = configMap.get(port);
            String res = getOnePortMessage(group, ip, port, protocol);
            metricDTOS.addAll(JsonMapper.fromJsonToList(res, MetricDTO.class));
        }

        return metricDTOS;
    }

    @SuppressWarnings("unchecked")
    protected void addMetricsConfigToMap(Map<String, String> configMap, String ip) {
        List<Provider> providers = providerService.findByAddress(ip);
        if (providers.size() > 0) {
            Provider provider = providers.get(0);
            String service = provider.getService();
            MetadataIdentifier providerIdentifier = new MetadataIdentifier(Tool.getInterface(service),
                Tool.getVersion(service), Tool.getGroup(service), Constants.PROVIDER_SIDE, provider.getApplication());
            String metaData = providerService.getProviderMetaData(providerIdentifier);
            FullServiceDefinition providerServiceDefinition =
                JsonMapper.fromJson(metaData, FullServiceDefinition.class);
            Map<String, String> parameters = providerServiceDefinition.getParameters();
            configMap.put(parameters.get(Constants.METRICS_PORT), parameters.get(Constants.METRICS_PROTOCOL));
        } else {
            List<Consumer> consumers = consumerService.findByAddress(ip);
            if (consumers.size() > 0) {
                Consumer consumer = consumers.get(0);
                String service = consumer.getService();
                MetadataIdentifier consumerIdentifier =
                    new MetadataIdentifier(Tool.getInterface(service), Tool.getVersion(service), Tool.getGroup(service),
                        Constants.CONSUMER_SIDE, consumer.getApplication());
                String metaData = consumerService.getConsumerMetadata(consumerIdentifier);
                Map<String, String> consumerParameters = JsonMapper.fromJson(metaData, Map.class);
                configMap.put(consumerParameters.get(Constants.METRICS_PORT),
                    consumerParameters.get(Constants.METRICS_PROTOCOL));
            }
        }
    }
}
